﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;
using Microsoft.Win32;

namespace SPHealth.SharePoint.HealthRules.SP.Rules.Configuration
{
    /*
     NOTE: There is already a like rule OOTB however it checks for 100GB, 200GB is the new 100GB. 
     */

    public class WarnSQLalias : SPHealthAnalysisRule
    {
        #region Locals
        private SPHealthAnalysisRuleAutomaticExecutionParameters _executionParameters;
        private string _failingDatabaseServers;
        #endregion

        #region Constructor
        /* not required */
        #endregion

        #region Fields

        public override string Summary
        {
            get { return "One or more database servers in the farm are not using a SQL connection alias."; }
        }

        public override string Explanation
        {
            get
            {
                return String.Format("The following database server(s) are not using a SQL connection alias:\r\n{0}", _failingDatabaseServers);
            }
        }

        public override string Remedy
        {
            get { return "To improve ease of maintenance, configure SQL Server connection aliases for each database server in your farm - see http://technet.microsoft.com/en-us/library/cc298801.aspx."; }
        }

        public override SPHealthCheckErrorLevel ErrorLevel
        {
            get { return SPHealthCheckErrorLevel.Warning; }
        }

        public override SPHealthCategory Category
        {
            get { return SPHealthCategory.Configuration; }
        }

        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                if (_executionParameters == null)
                {
                    _executionParameters = new SPHealthAnalysisRuleAutomaticExecutionParameters
                    {
                        Schedule = SPHealthCheckSchedule.Daily,
                        Scope = SPHealthCheckScope.All,
                        ServiceType = typeof(SPTimerService), //Tell SP if we want our own timer job or can we run with others...
                        RepairAutomatically = false
                    };
                }
                return _executionParameters;
            }
        }

        #endregion

        #region Methods

        public override SPHealthCheckStatus Check()
        {
            if (!SPFarm.Joined)
            {
                throw new InvalidOperationException();
            }

            _failingDatabaseServers = "";
            const string keyName = "SOFTWARE\\Microsoft\\MSSQLServer\\Client\\ConnectTo";

            // create a list of every unique server that sharepoint is using as a database server
            List<string> dbServers = new List<string>();

            // populate the list of unique servers
            foreach (SPServer server in SPFarm.Local.Servers)
            {
                SPDatabaseServiceInstanceCollection instances = new SPDatabaseServiceInstanceCollection(server);
                foreach (SPDatabaseServiceInstance instance in instances)
                {
                    foreach (SPDatabase database in instance.Databases)
                    {
                        if (!dbServers.Contains(database.Server.Name))
                            dbServers.Add(database.Server.Name);
                    }
                }

            }

            // check if an alias exists for each dbserver
            
            try
            {
                RegistryKey connectTo = Registry.LocalMachine.OpenSubKey(keyName);
                if (connectTo != null)
                {

                    // determine if an alias exists for our database server name
                    foreach (string dbServer in dbServers)
                    {
                        bool isAlias = false;

                        foreach (string valueName in connectTo.GetValueNames())
                        {
                            if (valueName.ToLower() == dbServer.ToLower())
                            {
                                isAlias = true;
                                break;
                            }
                        }

                        if (!isAlias)
                            _failingDatabaseServers += string.Format("{0}\r\n", dbServer);

                    }
                }
            }
            catch
            {
                _failingDatabaseServers = "No SQL connections alias can be found";
            }


            if (string.IsNullOrEmpty(_failingDatabaseServers))
                return SPHealthCheckStatus.Passed;

            return SPHealthCheckStatus.Failed;
        }

        #endregion
    }
}
